package fr.babos.graphic.components.controls.buttons 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import fr.babos.utils.ObjectUtils;
	import fr.babos.graphic.components.base.SkinableComponent;
	import org.osflash.signals.DeluxeSignal;
	import org.osflash.signals.events.GenericEvent;
	import org.osflash.signals.ISignal;
	
	/**
	 * @author ZoulouX
	 */
	public class GenericButton extends SkinableComponent 
	{
		/**
		 * Remplacer un clip par un bouton
		 * @param	pClip : Le clip a remplacé (doit être sur la scène)
		 * @param	pButtonClass : La classe du bouton remplaçant le clip
		 * @param	pClipName : Le nom de la propriété du bouton sur laquelle réafecter le clip supprimé (optionnel)
		 * @return : L'instance du bouton créé avec le clip ajouté.
		 */
		public static function replaceClipWithButton (pClip:DisplayObject, pButtonClass:Class, pClipName:String = null):GenericButton
		{
			var button:GenericButton = new pButtonClass();
			var clipParent:DisplayObjectContainer = pClip.parent;
			
			if (pClip.parent != null)
			{
				clipParent.removeChild(pClip);
			}
			
			button.x = pClip.x;
			button.y = pClip.y;
			
			pClip.x = 0;
			pClip.y = 0;
			
			if (pClipName != null)
				button[pClipName] = pClip;
			
			button.addChild(pClip);
			
			if (pClip.parent != null)
			{
				clipParent.addChild(button);
			}
			
			return button;
		}
		
		/**
		 * Le curseur part du bouton
		 */
		protected var _onOver				:DeluxeSignal			= new DeluxeSignal(this);
		
		/**
		 * Le curseur arrive au dessus du bouton
		 */
		protected var _onOut				:DeluxeSignal			= new DeluxeSignal(this);
		
		/**
		 * Le clic (ou touch) est enfoncé
		 */
		protected var _onDown				:DeluxeSignal			= new DeluxeSignal(this);
		
		/**
		 * Le clic (ou touch) est relâché sur le bouton
		 */
		protected var _onUp					:DeluxeSignal			= new DeluxeSignal(this);
		
		/**
		 * Le clic (ou touch) est relâché en dehors du bouton
		 */
		protected var _onUpOutside			:DeluxeSignal			= new DeluxeSignal(this);
		
		/**
		 * Si le curseur est au dessus
		 */
		protected var _mouseOver			:Boolean				= false;
		
		/**
		 * Si le clic est enfoncé
		 */
		protected var _mouseDown			:Boolean				= false;
		
		/**
		 * Les valeurs avant le disable
		 */
		protected var _paramsBeforeDisable	:Object					= {};
		
		/**
		 * Le curseur part du bouton
		 */
		public function get onOver ():ISignal { return _onOver; }
		
		/**
		 * Le curseur arrive au dessus du bouton
		 */
		public function get onOut ():ISignal { return _onOut; }
		
		/**
		 * Le clic (ou touch) est enfoncé
		 */
		public function get onDown ():ISignal { return _onDown; }
		
		/**
		 * Le clic (ou touch) est relâché sur le bouton
		 */
		public function get onUp ():ISignal { return _onUp; }
		
		/**
		 * Le clic (ou touch) est relâché en dehors du bouton
		 */
		public function get onUpOutside ():ISignal { return _onUpOutside; }
		
		/**
		 * Si la souris est au dessus du bouton
		 */
		public function get mouseOver ():Boolean { return _mouseOver; }
		
		/**
		 * Si la souris est pressée
		 */
		public function get mouseDown ():Boolean { return _mouseDown; }
		
		
		/**
		 * Le constructeur
		 */
		public function GenericButton (pSkinDefinition:Class = null, pButtonMode:Boolean = false, pMouseChildren:Boolean = false)
		{
			// Mode bouton
			buttonMode = pButtonMode;
			
			// Ne pas écouter sur les children
			mouseChildren = pMouseChildren;
			
			// Relayer
			super(pSkinDefinition);
		}
		
		/**
		 * Initialisation
		 */
		override protected function addedHandler (event:Event = null):void
		{
			// Relayer
			super.addedHandler(event);
			
			// Ecouter les events
			//addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			//addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
			//addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			addEventListener(MouseEvent.ROLL_OVER, mouseOverHandler);
			addEventListener(MouseEvent.ROLL_OUT, mouseOutHandler);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		}
		
		/**
		 * RollOver
		 */
		protected function mouseOverHandler (event:MouseEvent):void
		{
			// On est en rollOver
			_mouseOver = true;
			
			// RollOver
			doOver();
			
			// Dispatcher
			_onOver.dispatch(new GenericEvent());
		}
		
		/**
		 * RollOut
		 */
		protected function mouseOutHandler (event:MouseEvent):void
		{
			// On est plus en rollOver
			_mouseOver = false;
			
			// RollOut
			doOut();
			
			// Dispatcher
			_onOut.dispatch(new GenericEvent());
		}
		
		/**
		 * Clic enfoncé
		 */
		protected function mouseDownHandler (event:MouseEvent):void
		{
			// Ecouter le stage
			stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
			
			// Si le clic est enfoncée
			_mouseDown = true;
			
			// MouseDown
			doDown();
			
			// Dispatcher
			_onDown.dispatch(new GenericEvent());
		}
		
		/**
		 * Clic relâché sur le stage
		 */
		protected function stageMouseUpHandler (event:MouseEvent):void
		{
			// Ne plus écouter le stage
			stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
			
			// Le clic n'est plus enfoncé
			_mouseDown = false;
			
			// Si on est en dessus du bouton
			if (_mouseOver)
			{
				// MouseUp
				doUp();
				
				// Signaler qu'on a relaché au dessus
				_onUp.dispatch(new GenericEvent());
			}
			else
			{
				// MouseUpOutside
				doUpOutside();
				
				// Signaler qu'on a relaché en dehors
				_onUpOutside.dispatch(new GenericEvent());
			}
		}
		
		
		/**
		 * Suppression du bouton
		 */
		override public function dispose ():void
		{
			// Ecouter les events
			//removeEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			//removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
			removeEventListener(MouseEvent.ROLL_OVER, mouseOverHandler);
			removeEventListener(MouseEvent.ROLL_OUT, mouseOutHandler);
			removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
			
			// Supprimer tous les listeners
			_onOver.removeAll();
			_onOut.removeAll();
			_onDown.removeAll();
			_onUp.removeAll();
			_onUpOutside.removeAll();
			
			// Supprimer tous les signaux
			_onOver = null;
			_onOut = null;
			_onDown = null;
			_onUp = null;
			_onUpOutside = null;
		}
		
		/**
		 * RollOver
		 */
		protected function doOver ():void
		{
			
		}
		
		/**
		 * RollOut
		 */
		protected function doOut ():void
		{
			
		}
		
		/**
		 * MouseDown
		 */
		protected function doDown ():void
		{
			
		}
		
		/**
		 * MouseUp
		 */
		protected function doUp ():void
		{
			
		}
		
		/**
		 * MouseUpOutside
		 */
		protected function doUpOutside ():void
		{
			
		}
		
		/**
		 * Désactiver
		 */
		public function disable ():void
		{
			_paramsBeforeDisable = {
				mouseEnabled: mouseEnabled,
				mouseChildren: mouseChildren
			}
			
			mouseEnabled = false;
			mouseChildren = false;
		}
		
		/**
		 * Activer
		 */
		public function enable ():void
		{
			ObjectUtils.extra(this, _paramsBeforeDisable);
		}
	}
}